C 语言重学之旅 - 从 redis 中学习 C 语言

变量

  1. 变量: 其实只不过是程序可操作的存储区的名称.
  2. 类型: 变量存储的大小和布局
  3. 变量定义: 就是告诉编译器在何处创建变量的存储,以及如何创建变量的存储。
  4. 常量: #define 预处理器, 复制多份, const 直接定义一份
  5. 变量存储位置:
    1. 栈: 用来做函数调用, 参数传递等, 程序运行过程中操作最频繁的数据区.
    2. 全局静态区: 变量一直存在于内存, 整个运行中不会被销毁.
    3. 堆: 由操作系统维护的大空间伸缩区, 在程序运行中动态申请

类型

  1. const void * 万能不可修改数据指针
  2. size_t,全称应该是size type,就是说“一种用来记录大小的数据类型”, 一种“整型”类型, 不同平台的size_t会用不同的类型实现, 使用size_t而非int或unsigned可以写出扩展行更好的代码, 即是为了提供一种可移植的代码形式.

修饰符

  1. static
    1. 修饰局部变量时: 变量存储在全局静态区, 作用域局部
    2. 修饰全局变量时: 限定作用域为本文件可见
    3. 修饰函数时: 限定作用域为本文件

函数

  1. void memset(void s, int ch, size_t n); 将s中当前位置后面的n个字节 (typedef unsigned int size_t )用 ch 替换并返回 s .

编译器特性

  1. gcc -g main.c 在编译的时候,产生调试信息。
  2. gcc -E main.c > main.s, 只激活预处理
  3. gcc -S main.c 只激活预处理和汇编, 产生汇编代码
  4. gcc -c main.c 只激活预处理,编译,和汇编,也就是他只把程序做成obj文件
  5. attribute((packed)) 取消结构体在编译过程中的优化对齐,按尽可能小的size对齐——也就是按1字节为单位对齐

标准库

  1. libc
    1. void *memmove( void* dest, const void* src, size_t count ); 拷贝字节, 保证源串在被覆盖之前将重叠区域的字节拷贝到目标区域中.
    2. void *calloc(size_t __count, size_t __size) __result_use_check __alloc_size(1,2); 批量分配内存 size * size, 并自动初始化为0
    3. void *malloc(size_t __size) __result_use_check __alloc_size(1); 分配内存, 不初始化数据
    4. int snprintf(char* dest_str,size_t size,const char* format,...); 将可变参数 “…” 按照format的格式格式化为字符串,然后再将其拷贝至str中。
  2. <sys/time.h>, 系统时间相关库
    1. timeval {tv_sec, tv_usec} 秒和纳秒时间戳
    2. timezone {tz_minuteswest, tz_dsttime} 时区
    3. int gettimeofday(struct timeval *tv, struct timezone *tz); 获取当前时间戳
  3. <sys/termios.h>, 终端相关库
    1. int tcgetattr(int, struct termios *); 获取终端参数
  4. <sys/ioctl.h>, input/output control
    1. int ioctl(int, unsigned long, ...); 专用于设备输入输出操作的系统调用,该调用传入一个跟设备有关的请求码,系统调用的功能完全取决于请求码。
  5. <sys/fcntl.h>, 通过文件描述符, 操作稳健
    1. int fcntl(int, int, ...) __DARWIN_ALIAS_C(fcntl);, 获取\设置文件 flag, 锁等
  6. <sys/socket.h>
    1. SOCKET PASCAL FAR socket( int af, int type, int protocol); 创建套接字
      1. af 地址描述
      2. type 类型描述
      3. protocol 所用协议
    2. int connect(SOCKET s, const struct sockaddr * name, int namelen); 建立套接字链接
  1. <unistd.h>
    1. int isatty(int handle); 检查给定的设备类型, 普通文件 返回 0 ,设备 返回 -1
    2. ssize_t write(int __fd, const void * __buf, size_t __nbyte) __DARWIN_ALIAS_C(write); 写入数据
    3. ssize_t read(int, void *, size_t) __DARWIN_ALIAS_C(read); 读取数据
    4. pid_t getpid(void); 获取进程 ID
  2. <stdio.h>
    1. int fileno(FILE *); 返回文件描述符
  3. <stdlib.h>
    1. char *getenv(const char *); 获取 env 值
    2. long long strtoll(const char *__str, char **__endptr, int __base); 字符串转 long long
    3. int atoi(const char *); 字符串转数字. 按十进制理解字符串.
    4. double atof(const char *); 字符串转 double.
    5. int atexit(void (* _Nonnull)(void)); 用来注册执行exit()函数前执行的终止处理程序.
  4. <string.h>
    1. int strcmp(const char *__s1, const char *__s2); 两个字符串比较, s1 < s2 => < 0, s1 > s2 => >0, s1 = s2 => 0
    2. int strncasecmp(const char *, const char *, size_t); 不区分大小写比较前n个字符
    3. const char* strchr(const char* __s, int __c) 返回字符在字符串中第一次出现的位置, 没又返回一个NULL 指针
    4. char *strdup(const char *__s1); 字符串拷贝函数
  5. <sys/signal.h>
    1. void(*signal(int, void (*)(int)))(int); 系统信号处理函数, 第一个参数signum:指明了所要处理的信号类型,它可以取除了SIGKILL和SIGSTOP外的任何一种信号。第二个参数handler:描述了与信号关联的动作,它可以取以下三种值:
      1. SIG_IGN: 忽略该信号
      2. SIG_DFL: 恢复对信号的系统默认处理。不写此处理函数默认也是执行系统默认操作
      3. sighandler_t类型的函数指针
  6. <netdb.h>
    1. int getaddrinfo( const char hostname, const char service, const struct addrinfo *hints, struct addrinfo **result );
      1. hostname: 一个主机名或者地址串( IPv4 点分十进制串或者 IPv6 的16进制串)
      2. service: 服务名, 十进制端口号, 也可以是已定义的服务名称, 如 ftp\http
      3. hints: 一个空指针或者 addrinfo 结构体的指针, 填入关于期望返回的信息类型暗示, 例如将 ai_sockettype 设置为 SOCK_DGRAM 使得返回仅仅适用于数据报套接口的信息.
      4. result: 本函数通过 result指针返回一个指向 addrinfo 结构体链表的指针
      5. 返回值: 0 –成功, 非 0 –出错